#define _LINUX_

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include "Arbol/Arbol.h"


int cod_exit=0;


/* ******************************************************************************************** */


#define OP_AGREGAR 1
#define OP_MODIFICAR 2
#define OP_QUITAR 3
#define OP_BUSCAR 4

char* nombre_archivo=NULL;


/* AGREGA registro A LA LISTA DE registroS A INDEXAR */
int agregar_registro(const char* clave, const char* valor )
{

	string *valorStr = new string(valor);
	string claveString(clave);
	Clave claveObj(claveString);
	Elemento* elemento = new Elemento(claveObj,valorStr);
	Arbol* arbol = Arbol::getInstancia();
	arbol->insertarElemento(elemento);
	delete elemento;

	return cod_exit;
}


int modificar_registro(const char* clave, const char* valor )
{

	string valorStr = valor;
	string claveString(clave);
	Clave claveObj(claveString);
	Arbol* arbol = Arbol::getInstancia();
	arbol->modificarElemento(claveObj, &valorStr);
	return cod_exit;
}

int quitar_registro(const char* clave)
{
	string claveString(clave);
	Clave claveObj(claveString);
	Arbol* arbol = Arbol::getInstancia();
	arbol->quitarElemento(claveObj);

	return cod_exit;
}

int buscar_registro(const char* clave)
{
	string claveString(clave);
	Clave claveObj(claveString);
	Elemento* elemento;
	Arbol* arbol = Arbol::getInstancia();
	elemento = arbol->buscarElemento(claveObj);
	if (elemento!=NULL){
		cout<<"Elemento con clave: "<<elemento->getClave().getClave()<<" y valor: "<<*(elemento->getValor())<<endl;
	}
	else{

		cout <<"\nElemento con clave "<< clave << " no existe \n";
	}
	delete elemento;

	return cod_exit;
}

void elemento_siguiente(int desplazamiento){

	try{

		Elemento* elemento = Arbol::getInstancia()->getElementoContiguo(desplazamiento);

		if (elemento!=NULL){

			cout<<"\n Elemento con clave: "<<elemento->getClave().getClave()<<" y valor: "<<*(elemento->getValor())<<endl;
		}
		else{

			cout <<"\n Primero debe buscar un elemento \n";

		}
		delete elemento;
	}
	catch(ElementoUltimoException){

		cout <<"\n Se ha llegado al último Elemento\n";
	}
	catch(ElementoPrimeroException){

		cout <<"\n Se ha llegado al primer Elemento\n";
	}

}

int parser_registros( int operacion )
{

char buffer[2][LARGO_BLOQUE];
int pos_buffer[2];
int c;
int token=-1;

pos_buffer[0]=0;
pos_buffer[1]=0;


while ( ((c=getc(stdin))!=EOF)||(c==0) )
	{
	    switch (c) 
		{
    		    case  '(':  if(token==-1) token=0;
    			        break;
    			        
		    case  ';':  if (token==0) { token=1; 
		    				buffer[0][pos_buffer[0]]=0;
		    			       }	    
		    						                
		                break;
		    case  ')':  if (token==1) { token=2;
						buffer[1][pos_buffer[1]]=0;
					       }	
		                break;
		                
		    default  :  if ( ((token==0) || (token==1)) && (pos_buffer[token]<LARGO_BLOQUE-1))
								 buffer[token][pos_buffer[token]++]=c;		    
				else if (token==2)
					{
					 
					 if (operacion==OP_AGREGAR)
					 			agregar_registro ( (const char*) buffer[0] , (const char*) buffer[1] );

				         else if (operacion==OP_MODIFICAR)

				                                modificar_registro ( (const char*) buffer[0] , (const char*) buffer[1] );
				         else if (operacion==OP_QUITAR)
				                                quitar_registro ( (const char*) buffer[0] );

				         else if (operacion==OP_BUSCAR)
				                                buscar_registro ( (const char*) buffer[0] );

				                                
				         pos_buffer[0]=0;
					 pos_buffer[1]=0;

				         token=-1;
					}					
				break;            		                		                
		}				
	  
	}
	
return 0;
}


int listar_registro ()
{
	Arbol* arbol = Arbol::getInstancia();
	arbol->print();

	return cod_exit;

}





/* LINEA DE COMANDOS */
int mostrar_opciones (char * nombre_del_programa)
{
	  printf ("\nUsar: %s  NombreArchivo [opciones] ",nombre_del_programa);
	  printf ("\n-I clave valor\n\t Ingresa datos a la estructura");
	  printf ("\n-B clave \n\t Busca datos a la estructura");
	  printf ("\n-M clave valor\n\t Modifica datos a la estructura");
	  printf ("\n-Q clave \n\t Quita un dato de la estructura");
	  printf ("\n-S\n\t Vuelca los datos de la estructura a texto ");
	  
	  printf ("\n");
return 0;
}



int main (int argc, char **argv)
{

	/* Se le asigna un valor por defecto y el nombre "PruebaArbol" al archivo de almacenamiento */
	Arbol::setTamanioMaximoNodo(LARGO_BLOQUE);

	int arg_pl=0;
	int arg_pa=0;
	int arg_pd=0;
	int arg_pm=0;
	int arg_pb=0;
	int i;
	char* clave=NULL;
	char* valor=NULL;

    if (argc <= 2)
	{
    	mostrar_opciones (argv[0]);
    	return 0;
	}
    else
	{
	    nombre_archivo=argv[1];
	    
	    Arbol::setNombreArchivo(nombre_archivo);
	    for (i=2;i<argc;i++)
		{
	    	if(arg_pa)
	    	{
	    		if (clave==NULL) clave=argv[i];
	    		else
	    		{
	    			valor=argv[i];
	    			printf ("\n\tDato a agregar. clave: %s valor: %s \n",clave,valor);
	    			agregar_registro(clave,valor);
	    			arg_pa=0;
	    		}
	    	}
	    	else if(arg_pm)
	    	{
	    		if (clave==NULL) clave=argv[i];
	    		else
	    		{
	    			valor=argv[i];
	    			printf ("\n\tDato a modificar. clave: %s valor: %s \n",clave,valor);
	    			modificar_registro(clave,valor);
	    			arg_pm=0;
	    		}
	    	}

	    	else if(arg_pd)
	    	{
	    		clave=argv[i];
	    		printf ("\n\tDato a eliminar. %s\n",clave);
	    		quitar_registro(clave);
	    		arg_pd=0;
	    	}

	    	else if(arg_pb)
	    	{
	    		clave=argv[i];
	    		printf ("\n\tDato a buscar. %s\n",clave);
	    		buscar_registro(clave);
	    		arg_pb=0;
	    	}

	    	else if (!strcmp(argv[i],"-S"))
	    	{
	    		arg_pl=1;
	    		printf ("\n Opcion -S: Mostrar los datos de la estructura\n");
	    		listar_registro ();
	    	}

	    	else if (!strcmp(argv[i],"-I"))
	    	{
	    		if(i>=argc-1)
	    		{
	    			printf ("\n Opcion -I: Ingresar datos a la estructura (carga de stdin)\n");
	    			parser_registros(OP_AGREGAR);
	    		}
	    		else
	    		{
	    			arg_pa=1;
	    			printf ("\n Opcion -I: Ingresar datos a la estructura");
	    		}
	    	}
	    	else if (!strcmp(argv[i],"-N")){

	    		printf("\n Opcion -N: Elemento Siguiente\n");

	    		elemento_siguiente(Arbol::EDERECHO);

	    	}
	    	else if (!strcmp(argv[i],"-A")){

	    		printf("\n Opcion -A: Elemento Anterior\n");

	    		elemento_siguiente(Arbol::EIZQUIERDO);
	    	}
	    	else if (!strcmp(argv[i],"-M"))
	    		if(i>=argc-1)
	    		{
	    			printf ("\n Opcion -I: Ingresar datos a la estructura (carga de stdin)\n");
	    			parser_registros(OP_MODIFICAR);
	    		}
	    		else
	    		{
	    			arg_pm=1;
	    			printf ("\n Opcion -M: Modifica un dato de la estructura");
	    		}
		    				
	    	else if (!strcmp(argv[i],"-Q"))
	    		if(i>=argc-1)
	    		{
	    			printf ("\n Opcion -I: Ingresar datos a la estructura (carga de stdin)\n");
	    			parser_registros(OP_QUITAR);
	    		}
	    		else
	    		{
	    			arg_pd=1;
	    			printf ("\n Opcion -Q: Quita un dato de la estructura");
	    		}

	    	else if (!strcmp(argv[i],"-B"))
	    		if(i>=argc-1)
	    		{
	    			printf ("\n Opcion -B: Busca datos a la estructura (carga de stdin)\n");
	    			parser_registros(OP_BUSCAR);
	    		}
	    		else
	    		{
	    			arg_pb=1;
	    			printf ("\n Opcion -B: Busca un dato de la estructura");
	    		}
		    				
		    else if (!strcmp(argv[i],"-h"))
		    {
		    	mostrar_opciones (argv[0]);
		    }
		    else
		    {
		    	printf ("\n Opcion invalida\n");
		    	return(-1);
		    }
		}
	}

    Arbol::borrarInstancia();
    return (cod_exit);
}
